﻿using System.Threading;
using System.Threading.Tasks;

namespace ESRI.ArcGIS.Client.Tasks.Async
{
    public static partial class RouteTaskExtensions
    {
        #region Solve

        /// <summary>
        /// Determines the path from one stop to the next.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="routeParameters">Parameters indicate guidlines that are required when determining
        /// what the route to each stop.</param>
        /// <returns>a Task object with RouteResult upon successful completion. Otherwise, the Task.Exception is set.</returns>
        public static Task<RouteTaskResult> SolveTaskAsync(this RouteTask task,
            RouteParameters routeParameters)
        {
            return SolveTaskAsync(task, routeParameters, CancellationToken.None);
        }

        /// <summary>
        /// Determines the path from one stop to the next.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="routeParameters">Parameters indicate guidlines that are required when determining
        /// what the route to each stop.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns>a Task object with RouteResult upon successful completion. Otherwise, the Task.Exception is set.</returns>
        public static Task<RouteTaskResult> SolveTaskAsync(this RouteTask task,
            RouteParameters routeParameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<RouteTask, RouteEventArgs, RouteTaskResult>(
                t => t.SolveAsync(routeParameters, null),
                (t, e) => t.SolveCompleted += e,
                (t, e) => t.SolveCompleted -= e,
                e => new RouteTaskResult(e), 
                cancellationToken);
        }

        #endregion

        #region SolveClosestFacility

        /// <summary>
        /// Determines the closest route between Incidents and Facilities.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="routeClosestFacilityParameters">Parameters indicate guidlines that are required
        /// when determining what the route to the closest facility.</param>
        /// <returns></returns>
        public static Task<RouteTaskResult> SolveClosestFacilityTaskAsync(this RouteTask task,
            RouteClosestFacilityParameters routeClosestFacilityParameters)
        {
            return SolveClosestFacilityTaskAsync(task, routeClosestFacilityParameters, CancellationToken.None);
        }

        /// <summary>
        /// Determines the closest route between Incidents and Facilities.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="routeClosestFacilityParameters">Parameters indicate guidlines that are required
        /// when determining what the route to the closest facility.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<RouteTaskResult> SolveClosestFacilityTaskAsync(this RouteTask task,
            RouteClosestFacilityParameters routeClosestFacilityParameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<RouteTask, RouteEventArgs, RouteTaskResult>(
                t => t.SolveClosestFacilityAsync(routeClosestFacilityParameters),
                (t, e) => t.SolveClosestFacilityCompleted += e,
                (t, e) => t.SolveClosestFacilityCompleted -= e,
                e => new RouteTaskResult(e), 
                cancellationToken);
        }

        #endregion

        #region SolveServiceArea

        /// <summary>
        /// Returns geometries that define the service area of each facility.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="routeServiceAreaParameters">Parameters indicate guidelines that are required
        /// when determining what the service area is of each facility.</param>
        /// <returns></returns>
        public static Task<RouteTaskResult> SolveServiceAreaTaskAsync(this RouteTask task,
            RouteServiceAreaParameters routeServiceAreaParameters)
        {
            return SolveServiceAreaTaskAsync(task, routeServiceAreaParameters, CancellationToken.None);
        }

        /// <summary>
        /// Returns geometries that define the service area of each facility.
        /// </summary>
        /// <param name="task"></param>
        /// <param name="routeServiceAreaParameters">Parameters indicate guidelines that are required
        /// when determining what the service area is of each facility.</param>
        /// <param name="cancellationToken">Cancellation token for cancelling task.</param>
        /// <returns></returns>
        public static Task<RouteTaskResult> SolveServiceAreaTaskAsync(this RouteTask task,
            RouteServiceAreaParameters routeServiceAreaParameters, CancellationToken cancellationToken)
        {
            return task.HandleTask<RouteTask, RouteEventArgs, RouteTaskResult>(
                t => t.SolveServiceAreaAsync(routeServiceAreaParameters, null),
                (t, e) => t.SolveServiceAreaCompleted += e,
                (t, e) => t.SolveServiceAreaCompleted -= e,
                e => new RouteTaskResult(e), 
                cancellationToken);
        }

        #endregion

    }
}
